import random
import json
import pickle
import os
from abc import ABC, abstractmethod
import pygame

# Initialize font system
pygame.font.init()
font_names = ["Arial Unicode MS", "Arial", "Helvetica", "sans-serif"]
large_font = pygame.font.SysFont(font_names, 36)
medium_font = pygame.font.SysFont(font_names, 28)
small_font = pygame.font.SysFont(font_names, 20)

# Color definitions
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
GRAY = (150, 150, 150)
LIGHT_BLUE = (173, 216, 230)

# Chinese style color palette
CN_RED = (188, 33, 58)
CN_GOLD = (243, 173, 52)
CN_BLACK = (33, 33, 33)
CN_GREEN = (40, 110, 75)
CN_BLUE = (30, 57, 91)

# Screen settings
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("League of ChangAn")

# Global variables
selected_card = None
selected_minion = None
background_offset = 0
hovered_card = None  # For card hover information display
battle_log = []  # Battle log storage

# Default images
DEFAULT_CARD_IMAGE = pygame.Surface((80, 120))
DEFAULT_CARD_IMAGE.fill(CN_BLUE)
DEFAULT_CHARACTER_IMAGE = pygame.Surface((100, 150))
DEFAULT_CHARACTER_IMAGE.fill(CN_RED)
# Add simple character symbol to default image
pygame.draw.circle(DEFAULT_CHARACTER_IMAGE, WHITE, (50, 30), 20)  # Head
pygame.draw.rect(DEFAULT_CHARACTER_IMAGE, WHITE, (30, 50, 40, 70))  # Body

# Create Chinese style card border
CARD_BORDER = pygame.Surface((86, 126), pygame.SRCALPHA)
pygame.draw.rect(CARD_BORDER, CN_GOLD, (0, 0, 86, 126), 3)
pygame.draw.rect(CARD_BORDER, CN_GOLD, (5, 5, 76, 116), 1)

# Create button background
BUTTON_BG = pygame.Surface((160, 50), pygame.SRCALPHA)
BUTTON_BG.fill(CN_BLUE)
pygame.draw.rect(BUTTON_BG, CN_GOLD, (0, 0, 160, 50), 2)


class Card:
    """Card class representing both minions and spells"""
    def __init__(self, card_data, owner_name):
        self.name = card_data.get("name", "Unknown Card")
        self.description = card_data.get("description", "No description")
        self.cost = card_data.get("cost", 1)
        self.attack = card_data.get("attack", 0)
        self.health = card_data.get("health", 0)
        self.max_health = self.health
        self.effect = card_data.get("effect", None)
        self.type = card_data.get("type", "minion")
        self.owner = owner_name
        self.summoned_this_turn = False
        self.can_attack = False
        self.image = DEFAULT_CARD_IMAGE
        self.keywords = card_data.get("keywords", [])  # Card special abilities
        
    @property
    def is_minion(self):
        return self.type == "minion"
        
    @property
    def is_spell(self):
        return self.type == "spell"
        
    def is_alive(self):
        return self.health > 0
        
    def take_damage(self, amount):
        """Handle damage calculation and health updates"""
        old_health = self.health
        self.health = max(0, self.health - amount)
        is_dead = self.health == 0
        
        # Log health changes
        if old_health != self.health:
            add_battle_log(f"{self.name} took {amount} damage (HP: {old_health} → {self.health})")
        
        return is_dead
        
    def attack_target(self, target):
        if not self.can_attack or not self.is_alive():
            return False
            
        # Check if target is alive before attacking
        if not target.is_alive():
            add_battle_log(f"Cannot attack dead target: {target.name}")
            return False
            
        # Check if target has taunt keyword
        if target and hasattr(target, 'keywords') and "taunt" in target.keywords:
            add_battle_log(f"Must attack Taunt minion: {target.name}")
            
        # Minion attacks target
        target_dead = target.take_damage(self.attack)
        add_battle_log(f"{self.name} attacks {target.name} for {self.attack} damage")
        
        # Target counterattacks if still alive
        if hasattr(target, 'attack') and target.is_alive() and target.is_minion:
            self_dead = self.take_damage(target.attack)
            add_battle_log(f"{target.name} counterattacks {self.name} for {target.attack} damage")
            if self_dead:
                return True
                
        self.can_attack = False
        return target_dead
        
    def draw(self, surface, x, y, selected=False):
        """Draw the card on screen"""
        # Create card background
        card_bg = pygame.Surface((80, 120), pygame.SRCALPHA)
        if self.is_minion:
            card_bg.fill((20, 40, 80, 230))  # Minion card background
        else:
            card_bg.fill((60, 30, 30, 230))  # Spell card background
        
        # Draw card base
        surface.blit(card_bg, (x, y))
        
        # Draw decorative border
        surface.blit(CARD_BORDER, (x - 3, y - 3))
        
        # Selection highlight effect
        if selected:
            highlight = pygame.Surface((80, 120), pygame.SRCALPHA)
            highlight.fill((255, 255, 0, 80))
            surface.blit(highlight, (x, y))
            pygame.draw.rect(surface, CN_GOLD, (x - 3, y - 3, 86, 126), 4)
        
        # Draw card name - centered
        name_text = small_font.render(self.name, True, WHITE)
        name_rect = name_text.get_rect(center=(x + 40, y + 15))
        surface.blit(name_text, name_rect)
        
        # Draw mana cost with circular background
        cost_bg = pygame.Surface((20, 20), pygame.SRCALPHA)
        pygame.draw.circle(cost_bg, CN_GOLD, (10, 10), 10)
        surface.blit(cost_bg, (x + 5, y + 30))
        cost_text = small_font.render(f"{self.cost}", True, CN_BLACK)
        cost_rect = cost_text.get_rect(center=(x + 15, y + 40))
        surface.blit(cost_text, cost_rect)
        
        # For minions, show attack and health
        if self.is_minion:
            # Create circular backgrounds for stats
            atk_bg = pygame.Surface((30, 30), pygame.SRCALPHA)
            pygame.draw.circle(atk_bg, CN_RED, (15, 15), 15)
            surface.blit(atk_bg, (x + 5, y + 80))
            
            hp_bg = pygame.Surface((30, 30), pygame.SRCALPHA)
            pygame.draw.circle(hp_bg, GREEN, (15, 15), 15)
            surface.blit(hp_bg, (x + 45, y + 80))
            
            # Draw stat values
            attack_text = small_font.render(f"{self.attack}", True, WHITE)
            attack_rect = attack_text.get_rect(center=(x + 20, y + 95))
            surface.blit(attack_text, attack_rect)
            
            health_text = small_font.render(f"{self.health}", True, WHITE)
            health_rect = health_text.get_rect(center=(x + 60, y + 95))
            surface.blit(health_text, health_rect)
        else:
            # For spells, show truncated description
            desc_text = small_font.render(self.description[:15] + "...", True, WHITE)
            desc_rect = desc_text.get_rect(center=(x + 40, y + 70))
            surface.blit(desc_text, desc_rect)


class Champion(ABC):
    """Base class for all champions/heroes"""
    def __init__(self, name, health, skill, background, image_path=""):
        self.name = name
        self.max_health = health
        self.health = health
        self.skill = skill
        self.background = background
        self.skill_cooldown = 0
        self.armor = 0
        self.attack = 0  # Added missing attack attribute
        
        # Load character image with error handling
        self.image = self._load_image(image_path)
        
    def _load_image(self, image_path):
        """Helper method to load character images safely"""
        try:
            if image_path and os.path.exists(image_path):
                img = pygame.image.load(image_path).convert_alpha()
                return pygame.transform.scale(img, (100, 150))
            else:
                # Create a unique default image for each champion
                default_img = pygame.Surface((100, 150), pygame.SRCALPHA)
                default_img.fill(CN_RED)
                pygame.draw.circle(default_img, WHITE, (50, 30), 20)  # Head
                pygame.draw.rect(default_img, WHITE, (30, 50, 40, 70))  # Body
                return default_img
        except Exception as e:
            print(f"Error loading image: {e}")
            return DEFAULT_CHARACTER_IMAGE
            
    def reduce_cooldown(self):
        """Reduce skill cooldown by 1 each turn"""
        if self.skill_cooldown > 0:
            self.skill_cooldown -= 1
            
    def is_skill_ready(self):
        """Check if skill is off cooldown"""
        return self.skill_cooldown == 0
        
    @abstractmethod
    def use_skill(self, player, opponent, target=None):
        """Abstract method for skill usage"""
        pass
        
    def draw_character(self, screen, x, y):
        """Draw champion on screen"""
        screen.blit(self.image, (x, y))


class GeneralLi(Champion):
    """Warrior champion with direct damage skill"""
    def use_skill(self, player, opponent, target=None):
        if not self.is_skill_ready():
            add_battle_log(f"{self.name}'s skill not ready (cooldown: {self.skill_cooldown})")
            return False
            
        # Deal damage to enemy champion
        damage = self.skill.get("value", 5)
        opponent.health -= damage
        add_battle_log(f"{self.name} uses {self.skill['name']}, dealing {damage} damage to {opponent.name}")
        
        # Set cooldown
        self.skill_cooldown = 3
        return True


class HealerWang(Champion):
    """Support champion with healing skill"""
    def use_skill(self, player, opponent, target=None):
        if not self.is_skill_ready():
            add_battle_log(f"{self.name}'s skill not ready (cooldown: {self.skill_cooldown})")
            return False
            
        # Heal self
        heal_amount = self.skill.get("value", 4)
        player.health = min(player.max_health, player.health + heal_amount)
        add_battle_log(f"{self.name} uses {self.skill['name']}, restoring {heal_amount} health")
        
        # Set cooldown
        self.skill_cooldown = 2
        return True


class LadyLin(Champion):
    """Ranger champion with single target damage"""
    def use_skill(self, player, opponent, target=None):
        if not self.is_skill_ready():
            add_battle_log(f"{self.name}'s skill not ready (cooldown: {self.skill_cooldown})")
            return False
            
        if not target and opponent.board:
            target = random.choice(opponent.board)
            
        if target and target.is_alive():
            damage = self.skill.get("value", 3)
            target.take_damage(damage)
            add_battle_log(f"{self.name} uses {self.skill['name']}, dealing {damage} damage to {target.name}")
            
            # Set cooldown
            self.skill_cooldown = 2
            return True
        else:
            add_battle_log("No valid target for skill")
            return False


class AlchemistZhou(Champion):
    """Mage champion with buffing skill"""
    def use_skill(self, player, opponent, target=None):
        if not self.is_skill_ready():
            add_battle_log(f"{self.name}'s skill not ready (cooldown: {self.skill_cooldown})")
            return False
            
        if not target and player.board:
            target = random.choice(player.board)
            
        if target and target.is_alive():
            buff_amount = self.skill.get("value", 2)
            target.attack += buff_amount
            target.health += buff_amount
            target.max_health += buff_amount
            add_battle_log(f"{self.name} uses {self.skill['name']}, {target.name} gains +{buff_amount}/+{buff_amount}")
            
            # Set cooldown
            self.skill_cooldown = 3
            return True
        else:
            add_battle_log("No valid target for skill")
            return False


class Item:
    """Item class for equipment bonuses"""
    def __init__(self, name, description, attack_bonus=0, health_bonus=0, armor_bonus=0):
        self.name = name
        self.description = description
        self.attack_bonus = attack_bonus
        self.health_bonus = health_bonus
        self.armor_bonus = armor_bonus
        
    def equip(self, champion):
        """Apply item bonuses to champion"""
        champion.attack += self.attack_bonus
        champion.max_health += self.health_bonus
        champion.health += self.health_bonus
        champion.armor += self.armor_bonus
        return True
        
    def unequip(self, champion):
        """Remove item bonuses from champion"""
        champion.attack -= self.attack_bonus
        champion.max_health -= self.health_bonus
        champion.health = max(1, champion.health - self.health_bonus)
        champion.armor -= self.armor_bonus
        return True


def create_default_items():
    """Create a set of default items"""
    return [
        Item("Iron Sword", "Increases attack power", attack_bonus=2),
        Item("Leather Armor", "Increases defense", armor_bonus=2),
        Item("Healing Potion", "Increases maximum health", health_bonus=5),
        Item("Steel Sword", "Greatly increases attack power", attack_bonus=4),
        Item("Steel Armor", "Greatly increases defense", armor_bonus=4),
        Item("Greater Potion", "Greatly increases maximum health", health_bonus=10)
    ]


class Player:
    """Player class managing all player-related data and actions"""
    def __init__(self, name, champion):
        self.name = name
        self.champion = champion  # Champion instance
        self.mana = 3  # Initial mana
        self.max_mana = 3  # Initial maximum mana
        self.hand = []
        self.board = []
        self.deck = []
        self.opponent = None
        self.turn_ended = False
        self.items = []  # Inventory items
        self.equipped_items = []  # Equipped items
        self.max_equipped = 2  # Maximum equipped items
        self.turn_count = 0  # Turn counter
        
    @property
    def health(self):
        return self.champion.health
        
    @health.setter
    def health(self, value):
        self.champion.health = max(0, min(value, self.champion.max_health))
    
    @property
    def max_health(self):
        return self.champion.max_health
    
    @property
    def armor(self):
        return self.champion.armor
    
    @armor.setter
    def armor(self, value):
        self.champion.armor = value
    
    def load_character_image(self):
        return self.champion.image
    
    def draw_character(self, screen, x, y):
        """Draw player champion with status information"""
        self.champion.draw_character(screen, x, y)
        
        # Draw champion name and health
        name_text = medium_font.render(self.champion.name, True, WHITE)
        screen.blit(name_text, (x + 120, y + 10))
        
        # Health bar display
        health_bar_width = 200
        health_percent = self.health / self.max_health if self.max_health > 0 else 0
        pygame.draw.rect(screen, RED, (x + 120, y + 50, health_bar_width, 20))
        pygame.draw.rect(screen, GREEN, (x + 120, y + 50, health_bar_width * health_percent, 20))
        health_text = small_font.render(f"HP: {self.health}/{self.max_health}", True, WHITE)
        health_rect = health_text.get_rect(center=(x + 220, y + 60))
        screen.blit(health_text, health_rect)
        
        # Draw skill information
        skill_text = small_font.render(f"Skill: {self.champion.skill['description']}", True, WHITE)
        screen.blit(skill_text, (x + 120, y + 80))
        
        # Draw skill cooldown
        if self.champion.skill_cooldown > 0:
            cooldown_text = small_font.render(f"Cooldown: {self.champion.skill_cooldown}", True, CN_RED)
            screen.blit(cooldown_text, (x + 120, y + 110))
    
    def init_deck(self, cards_data):
        """Initialize and shuffle player deck"""
        self.deck = [Card(c, self.name) for c in cards_data]
        random.shuffle(self.deck)
    
    def draw_card(self, num=1):
        """Draw cards from deck to hand"""
        for _ in range(num):
            if self.deck:
                card = self.deck.pop()
                self.hand.append(card)
                add_battle_log(f"{self.name} draws {card.name}")
            else:
                self.health = max(0, self.health - 1)
                add_battle_log(f"{self.name}'s deck is empty! Takes 1 damage")
    
    def start_turn(self):
        """Initialize a new turn for the player"""
        self.turn_ended = False
        self.turn_count += 1
        
        # Mana growth curve: faster early, slower later
        if self.turn_count <= 5:
            self.max_mana = min(10, self.max_mana + 1)
        elif self.turn_count % 2 == 0:  # Increase every 2 turns after
            self.max_mana = min(10, self.max_mana + 1)
            
        self.mana = self.max_mana
        
        # Reduce skill cooldown
        self.champion.reduce_cooldown()
        
        # Reset minion attack status
        for minion in self.board:
            minion.can_attack = True
            minion.summoned_this_turn = False
        
        self.draw_card(1)
        add_battle_log(f"{self.name}'s turn starts, gains {self.mana} mana (Turn {self.turn_count})")
    
    def end_turn(self):
        """Clean up at the end of turn"""
        self.turn_ended = True
        add_battle_log(f"{self.name} ends turn")
        
        # Remove dead minions
        dead_minions = [m for m in self.board if not m.is_alive()]
        for minion in dead_minions:
            add_battle_log(f"{minion.name} has fallen")
        self.board = [m for m in self.board if m.is_alive()]
    
    def can_play_card(self, card):
        """Check if player can play a card"""
        return self.mana >= card.cost
    
    def play_card(self, card):
        """Play a card from hand"""
        if card not in self.hand:
            return False
        if not self.can_play_card(card):
            add_battle_log(f"{self.name} doesn't have enough mana to play {card.name}")
            return False
        
        if card.is_minion and len(self.board) >= 7:
            add_battle_log("Battlefield is full, cannot summon more minions")
            return False
        
        self.hand.remove(card)
        self.mana -= card.cost
        
        if card.is_minion:
            card.summoned_this_turn = True
            self.board.append(card)
            add_battle_log(f"{self.name} plays {card.name}")
            # Apply keyword effects
            apply_keyword_effects(card)
            return True
        else:
            # Process spell card
            return self.resolve_spell(card)
    
    def resolve_spell(self, card):
        """Process spell card effects"""
        add_battle_log(f"{self.name} casts {card.name}")
        
        # Extended spell effect processing
        if card.effect == "deal_6_damage":
            if self.opponent.board:
                target = random.choice(self.opponent.board)
                target.take_damage(6)
                add_battle_log(f"{card.name} deals 6 damage to {target.name}")
            else:
                self.opponent.health -= 6
                add_battle_log(f"{card.name} deals 6 damage to {self.opponent.name}")
                
        elif card.effect == "heal_5":
            self.health = min(self.max_health, self.health + 5)
            add_battle_log(f"{self.name} restored 5 health")
            
        elif card.effect == "draw_2_cards":
            self.draw_card(2)
            add_battle_log(f"{self.name} draws 2 cards")
            
        elif card.effect == "deal_2_damage_to_all_enemies":
            for minion in self.opponent.board:
                minion.take_damage(2)
            add_battle_log(f"{card.name} deals 2 damage to all enemy minions")
            
        else:
            # Default effect processing
            if card.effect == "heal":
                self.health += 3
                add_battle_log(f"{self.name} restored 3 health")
            elif card.effect == "damage":
                self.opponent.health -= 3
                add_battle_log(f"{self.opponent.name} took 3 damage")
            elif card.effect == "buff":
                if self.board:
                    minion = random.choice(self.board)
                    minion.attack += 2
                    minion.health += 2
                    minion.max_health += 2
                    add_battle_log(f"{minion.name} gained +2/+2")
                else:
                    add_battle_log("No minions to buff")
        return True
    
    def use_champion_skill(self, target=None):
        """Use champion's special skill"""
        return self.champion.use_skill(self, self.opponent, target)
    
    def add_item(self, item):
        """Add item to inventory"""
        if isinstance(item, Item):
            self.items.append(item)
            return True
        return False
    
    def equip_item(self, item):
        """Equip an item from inventory"""
        if item not in self.items:
            return False
            
        if len(self.equipped_items) >= self.max_equipped:
            add_battle_log("Cannot equip more items")
            return False
            
        if item.equip(self.champion):
            self.items.remove(item)
            self.equipped_items.append(item)
            add_battle_log(f"{self.name} equipped {item.name}")
            return True
        return False
    
    def unequip_item(self, item):
        """Unequip an item"""
        if item not in self.equipped_items:
            return False
            
        if item.unequip(self.champion):
            self.equipped_items.remove(item)
            self.items.append(item)
            add_battle_log(f"{self.name} unequipped {item.name}")
            return True
        return False


def add_battle_log(message):
    """Add message to battle log (keep last 10 entries)"""
    battle_log.append(message)
    if len(battle_log) > 10:
        battle_log.pop(0)


# Create champion instance from data
def create_champion_from_data(data):
    champion_name = data["name"]
    
    # Use locally defined champion classes
    if champion_name == "General Li":
        return GeneralLi(** data)
    elif champion_name == "Healer Wang":
        return HealerWang(**data)
    elif champion_name == "Lady Lin":
        return LadyLin(** data)
    elif champion_name == "Alchemist Zhou":
        return AlchemistZhou(**data)
    else:
        # Default to General Li if champion not found
        return GeneralLi(** data)


# Initialize game
def init_game():
    """Initialize game with players and starting state"""
    # Character data with fallback
    characters_data = [
        {"name": "General Li", "health": 30, "skill": {"name": "Charge", "description": "Deal 5 damage to enemy champion", "value": 5}, 
         "background": "The great general defending Chang'an", "image_path": "images/li_jiangjun.png"},
        {"name": "Healer Wang", "health": 25, "skill": {"name": "Heal", "description": "Restore 4 health to yourself", "value": 4}, 
         "background": "A wandering physician", "image_path": "images/wang_shenyi.png"},
        {"name": "Lady Lin", "health": 22, "skill": {"name": "Precise Shot", "description": "Deal 3 damage to enemy minion", "value": 3}, 
         "background": "Agile archer", "image_path": "images/lin_nvxia.png"},
        {"name": "Alchemist Zhou", "health": 20, "skill": {"name": "Empower", "description": "Give a minion +2/+2", "value": 2}, 
         "background": "Wise alchemist", "image_path": "images/zhou_daoshi.png"}
    ]

    # Card data with fallback
    cards_data = [
        {"name": "Foot Soldier", "description": "Basic infantry unit", "cost": 1, "attack": 1, "health": 1, "type": "minion"},
        {"name": "Archer", "description": "Ranged attacker", "cost": 2, "attack": 2, "health": 1, "type": "minion", "keywords": ["charge"]},
        {"name": "Fireball", "description": "Deal 3 damage", "cost": 2, "effect": "damage", "type": "spell"},
        {"name": "Healing Spell", "description": "Restore 3 health", "cost": 2, "effect": "heal", "type": "spell"},
        {"name": "Knight", "description": "Heavily armored warrior", "cost": 3, "attack": 2, "health": 3, "type": "minion", "keywords": ["taunt"]},
        {"name": "Mage", "description": "Master of elemental magic", "cost": 4, "attack": 3, "health": 2, "type": "minion"},
        {"name": "Lightning Storm", "description": "Deal 2 damage to all enemy minions", "cost": 3, "effect": "deal_2_damage_to_all_enemies", "type": "spell"},
        {"name": "Greater Heal", "description": "Restore 5 health", "cost": 3, "effect": "heal_5", "type": "spell"},
        {"name": "Elite Warrior", "description": "Veteran combatant", "cost": 5, "attack": 4, "health": 4, "type": "minion", "keywords": ["charge"]},
        {"name": "Flame Strike", "description": "Deal 6 damage", "cost": 4, "effect": "deal_6_damage", "type": "spell"},
        {"name": "Recruit", "description": "Draw 2 cards", "cost": 3, "effect": "draw_2_cards", "type": "spell"},
        {"name": "Inspire", "description": "Give a minion +2/+2", "cost": 2, "effect": "buff", "type": "spell"}
    ]

    # Create champions
    champions = [create_champion_from_data(data) for data in characters_data]

    # Create players
    player1 = Player("Player", champions[0])
    player1.init_deck(cards_data)
    player1.draw_card(4)  # Initial hand

    # Create computer player
    player2 = Player("Computer", champions[1])
    player2.init_deck(cards_data)
    player2.draw_card(4)  # Computer initial hand

    # Set opponents
    player1.opponent = player2
    player2.opponent = player1

    # Initial items
    default_items = create_default_items()
    for i in range(3):
        player1.add_item(default_items[i])
        player2.add_item(default_items[i+3])

    return player1, player2


# Game state saving and loading
def save_game_state(player1, player2, filename="savegame.dat"):
    """Save current game state to file"""
    try:
        game_state = {
            "player1": {
                "name": player1.name,
                "champion": player1.champion,
                "health": player1.health,
                "mana": player1.mana,
                "max_mana": player1.max_mana,
                "armor": player1.armor,
                "hand": player1.hand,
                "board": player1.board,
                "deck": player1.deck,
                "items": player1.items,
                "equipped_items": player1.equipped_items,
                "turn_count": player1.turn_count
            },
            "player2": {
                "name": player2.name,
                "champion": player2.champion,
                "health": player2.health,
                "mana": player2.mana,
                "max_mana": player2.max_mana,
                "armor": player2.armor,
                "hand": player2.hand,
                "board": player2.board,
                "deck": player2.deck,
                "items": player2.items,
                "equipped_items": player2.equipped_items,
                "turn_count": player2.turn_count
            }
        }
        
        with open(filename, "wb") as f:
            pickle.dump(game_state, f)
        
        add_battle_log("Game saved successfully")
        return True
    except Exception as e:
        print(f"Error saving game: {e}")
        add_battle_log("Failed to save game")
        return False


def load_game_state(filename="savegame.dat"):
    """Load game state from file"""
    try:
        if not os.path.exists(filename):
            add_battle_log("No save file found")
            return None
            
        with open(filename, "rb") as f:
            game_state = pickle.load(f)
        
        # Rebuild players
        player1 = Player(game_state["player1"]["name"], game_state["player1"]["champion"])
        player2 = Player(game_state["player2"]["name"], game_state["player2"]["champion"])
        
        # Restore state
        for key, value in game_state["player1"].items():
            if key not in ["name", "champion"]:
                setattr(player1, key, value)
        
        for key, value in game_state["player2"].items():
            if key not in ["name", "champion"]:
                setattr(player2, key, value)
        
        # Set opponents
        player1.opponent = player2
        player2.opponent = player1

        add_battle_log("Game loaded successfully")
        return player1, player2
    except Exception as e:
        print(f"Error loading game: {e}")
        add_battle_log("Failed to load game")
        return None


# Card keyword system
def apply_keyword_effects(card, target=None):
    """Apply effects from card keywords"""
    if "taunt" in card.keywords:
        add_battle_log(f"{card.name} has Taunt (must be attacked first)")
    
    if "elusive" in card.keywords:
        add_battle_log(f"{card.name} has Elusive (hard to target)")
    
    if "charge" in card.keywords and card.is_minion:
        card.can_attack = True
        card.summoned_this_turn = False
        add_battle_log(f"{card.name} has Charge (can attack immediately)")


# Draw Chinese style decorations
def draw_chinese_decorations(surface):
    """Draw decorative elements with Chinese aesthetic"""
    # Draw border patterns
    pygame.draw.rect(surface, CN_GOLD, (10, 10, SCREEN_WIDTH - 20, SCREEN_HEIGHT - 20), 3)
    pygame.draw.rect(surface, CN_GOLD, (15, 15, SCREEN_WIDTH - 30, SCREEN_HEIGHT - 30), 1)
    
    # Draw corner decorations
    corner_size = 50
    # Top left
    pygame.draw.polygon(surface, CN_GOLD, [(10, 10), (10 + corner_size, 10), (10, 10 + corner_size)], 3)
    # Top right
    pygame.draw.polygon(surface, CN_GOLD, [(SCREEN_WIDTH - 10, 10), (SCREEN_WIDTH - 10 - corner_size, 10), (SCREEN_WIDTH - 10, 10 + corner_size)], 3)
    # Bottom left
    pygame.draw.polygon(surface, CN_GOLD, [(10, SCREEN_HEIGHT - 10), (10 + corner_size, SCREEN_HEIGHT - 10), (10, SCREEN_HEIGHT - 10 - corner_size)], 3)
    # Bottom right
    pygame.draw.polygon(surface, CN_GOLD, [(SCREEN_WIDTH - 10, SCREEN_HEIGHT - 10), (SCREEN_WIDTH - 10 - corner_size, SCREEN_HEIGHT - 10), (SCREEN_WIDTH - 10, SCREEN_HEIGHT - 10 - corner_size)], 3)


# Draw card detailed information
def draw_card_tooltip(surface, card, x, y):
    """Draw detailed card information tooltip"""
    # Create tooltip background
    width = 250
    height = 180
    tooltip_bg = pygame.Surface((width, height), pygame.SRCALPHA)
    tooltip_bg.fill((33, 33, 33, 240))
    pygame.draw.rect(tooltip_bg, CN_GOLD, (0, 0, width, height), 2)
    
    # Calculate position to stay on screen
    display_x = x + 50
    display_y = y - height - 10
    if display_y < 0:
        display_y = y + 130
    if display_x + width > SCREEN_WIDTH:
        display_x = SCREEN_WIDTH - width
    
    surface.blit(tooltip_bg, (display_x, display_y))
    
    # Draw card name
    name_text = medium_font.render(card.name, True, CN_GOLD)
    surface.blit(name_text, (display_x + 10, display_y + 10))
    
    # Draw cost
    cost_text = small_font.render(f"Cost: {card.cost}", True, WHITE)
    surface.blit(cost_text, (display_x + 10, display_y + 40))
    
    # Draw card type
    type_text = small_font.render(f"Type: {'Minion' if card.is_minion else 'Spell'}", True, WHITE)
    surface.blit(type_text, (display_x + 10, display_y + 65))
    
    # For minions, show attack and health
    if card.is_minion:
        stats_text = small_font.render(f"Attack: {card.attack}, Health: {card.health}/{card.max_health}", True, WHITE)
        surface.blit(stats_text, (display_x + 10, display_y + 90))
    
    # Draw description with word wrapping
    words = card.description.split(' ')
    lines = []
    current_line = ""
    
    for word in words:
        test_line = current_line + word + " "
        if small_font.size(test_line)[0] < width - 30:
            current_line = test_line
        else:
            lines.append(current_line)
            current_line = word + " "
    if current_line:
        lines.append(current_line)
    
    # Draw wrapped description text
    desc_y = display_y + 115 if card.is_minion else display_y + 90
    for line in lines[:4]:  # Limit to 4 lines
        desc_text = small_font.render(line, True, WHITE)
        surface.blit(desc_text, (display_x + 10, desc_y))
        desc_y += 20


# Draw game state
def draw_game_state(player, opponent):
    """Draw all game elements to screen"""
    global hovered_card
    
    # Draw gradient background
    background_rect = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
    for y in range(SCREEN_HEIGHT):
        # Top to bottom gradient - red to blue
        r = int(100 + 30 * (1 - y/SCREEN_HEIGHT))
        g = int(20 + 20 * (1 - y/SCREEN_HEIGHT))
        b = int(20 + 80 * (y/SCREEN_HEIGHT))
        a = 255
        pygame.draw.line(background_rect, (r, g, b, a), (0, y), (SCREEN_WIDTH, y))
    screen.blit(background_rect, (0, 0))
    
    # Draw decorative elements
    for i in range(50):
        x = (i * 37 + background_offset) % SCREEN_WIDTH
        y = (i * 19) % SCREEN_HEIGHT
        # Twinkling effect
        brightness = (pygame.time.get_ticks() // 100 + i) % 5
        pygame.draw.circle(screen, (243, 173, 52, 150 + brightness * 20), (x, y), 1 + brightness // 2)
    
    # Draw Chinese style decorations
    draw_chinese_decorations(screen)
    
    # Draw player area
    player_area = pygame.Surface((SCREEN_WIDTH, 300), pygame.SRCALPHA)
    player_area.fill((30, 57, 91, 200))  # Semi-transparent blue
    screen.blit(player_area, (0, 500))
    pygame.draw.rect(screen, CN_GOLD, (0, 500, SCREEN_WIDTH, 300), 2)
    
    # Draw opponent area
    opponent_area = pygame.Surface((SCREEN_WIDTH, 300), pygame.SRCALPHA)
    opponent_area.fill((188, 33, 58, 200))  # Semi-transparent red
    screen.blit(opponent_area, (0, 0))
    pygame.draw.rect(screen, CN_GOLD, (0, 0, SCREEN_WIDTH, 300), 2)
    
    # Draw battlefield area
    battlefield_area = pygame.Surface((SCREEN_WIDTH, 200), pygame.SRCALPHA)
    battlefield_area.fill((40, 110, 75, 200))  # Semi-transparent green
    screen.blit(battlefield_area, (0, 300))
    pygame.draw.rect(screen, CN_GOLD, (0, 300, SCREEN_WIDTH, 200), 2)
    
    # Draw player champion
    player.draw_character(screen, 50, 520)
    
    # Draw opponent champion
    opponent.draw_character(screen, 50, 20)
    
    # Draw player hand
    hand_y = 680
    hovered_card = None
    mouse_pos = pygame.mouse.get_pos()
    
    for i, card in enumerate(player.hand):
        card_x = 200 + i * 90
        card_rect = pygame.Rect(card_x, hand_y, 80, 120)
        
        # Check for mouse hover
        if card_rect.collidepoint(mouse_pos):
            hovered_card = card
            # Draw hover effect
            hover_effect = pygame.Surface((80, 120), pygame.SRCALPHA)
            hover_effect.fill((255, 255, 255, 50))
            screen.blit(hover_effect, (card_x, hand_y - 10))
            card.draw(screen, card_x, hand_y - 10, selected=(selected_card == card))
        else:
            card.draw(screen, card_x, hand_y, selected=(selected_card == card))
    
    # Draw player mana
    mana_bg = pygame.Surface((150, 40), pygame.SRCALPHA)
    mana_bg.fill((30, 57, 91, 200))
    pygame.draw.rect(mana_bg, CN_GOLD, (0, 0, 150, 40), 2)
    screen.blit(mana_bg, (800, 520))
    mana_text = medium_font.render(f"Mana: {player.mana}/{player.max_mana}", True, CN_GOLD)
    mana_rect = mana_text.get_rect(center=(875, 540))
    screen.blit(mana_text, mana_rect)
    
    # Draw player minions
    board_y = 350
    for i, minion in enumerate(player.board):
        minion_x = 200 + i * 90
        minion_rect = pygame.Rect(minion_x, board_y, 80, 120)
        
        # Check for mouse hover
        if minion_rect.collidepoint(mouse_pos):
            hovered_card = minion
            # Draw hover effect
            hover_effect = pygame.Surface((80, 120), pygame.SRCALPHA)
            hover_effect.fill((255, 255, 255, 50))
            screen.blit(hover_effect, (minion_x, board_y - 10))
            minion.draw(screen, minion_x, board_y - 10, selected=(selected_minion == minion))
        else:
            minion.draw(screen, minion_x, board_y, selected=(selected_minion == minion))
    
    # Draw opponent minions
    opp_board_y = 100
    for i, minion in enumerate(opponent.board):
        minion.draw(screen, 200 + i * 90, opp_board_y)
    
    # Draw battle log
    log_bg = pygame.Surface((300, 250), pygame.SRCALPHA)
    log_bg.fill((33, 33, 33, 220))
    pygame.draw.rect(log_bg, CN_GOLD, (0, 0, 300, 250), 2)
    screen.blit(log_bg, (800, 320))
    
    log_title = small_font.render("Battle Log:", True, CN_GOLD)
    screen.blit(log_title, (810, 320))
    
    for i, log in enumerate(battle_log):
        log_text = small_font.render(log, True, WHITE)
        screen.blit(log_text, (810, 345 + i * 21))
    
    # Draw buttons
    end_turn_btn = pygame.Rect(1000, 680, 150, 40)
    screen.blit(BUTTON_BG, (995, 675))
    end_turn_text = medium_font.render("End Turn", True, CN_GOLD)
    screen.blit(end_turn_text, (end_turn_btn.centerx - end_turn_text.get_width()//2, 
                               end_turn_btn.centery - end_turn_text.get_height()//2))
    
    save_btn = pygame.Rect(1000, 620, 150, 40)
    screen.blit(BUTTON_BG, (995, 615))
    save_text = medium_font.render("Save Game", True, CN_GOLD)
    screen.blit(save_text, (save_btn.centerx - save_text.get_width()//2, 
                           save_btn.centery - save_text.get_height()//2))
    
    load_btn = pygame.Rect(1000, 560, 150, 40)
    screen.blit(BUTTON_BG, (995, 555))
    load_text = medium_font.render("Load Game", True, CN_GOLD)
    screen.blit(load_text, (load_btn.centerx - load_text.get_width()//2, 
                           load_btn.centery - load_text.get_height()//2))
    
    # Apply button
    apply_btn = pygame.Rect(1000, 500, 150, 40)
    screen.blit(BUTTON_BG, (995, 495))
    apply_btn_text = medium_font.render("Apply Effect", True, CN_GOLD)
    screen.blit(apply_btn_text, (apply_btn.centerx - apply_btn_text.get_width()//2, 
                                apply_btn.centery - apply_btn_text.get_height()//2))
    
    # Draw card tooltip if hovering
    if hovered_card:
        # Find card position
        for i, card in enumerate(player.hand):
            if card == hovered_card:
                draw_card_tooltip(screen, card, 200 + i * 90, 680)
                break
        else:
            for i, minion in enumerate(player.board):
                if minion == hovered_card:
                    draw_card_tooltip(screen, minion, 200 + i * 90, 350)
                    break
    
    return end_turn_btn, save_btn, load_btn, apply_btn


# Computer AI logic
def computer_turn(computer, player):
    """Handle computer player's turn with AI logic"""
    computer.start_turn()
    
    # AI Strategy 1: Use champion skill if available
    if computer.champion.is_skill_ready():
        target = None
        if hasattr(computer.champion, 'use_skill'):
            # Smart target selection based on champion type
            if isinstance(computer.champion, LadyLin) and player.board:
                # Prioritize high-threat targets
                target = max(player.board, key=lambda m: m.attack, default=None)
            elif isinstance(computer.champion, AlchemistZhou) and computer.board:
                # Prioritize buffing strong minions
                target = max(computer.board, key=lambda m: m.attack, default=None)
            elif isinstance(computer.champion, HealerWang) and computer.health < computer.max_health * 0.7:
                # Heal when health is low
                target = None
                
        if computer.use_champion_skill(target):
            add_battle_log(f"Computer uses {computer.champion.name}'s skill")
    
    # AI Strategy 2: Play cards strategically
    playable_cards = [card for card in computer.hand if computer.can_play_card(card)]
    
    # Prioritize high-value cards
    playable_cards.sort(key=lambda c: c.attack + c.health if c.is_minion else 3, reverse=True)
    
    for card in playable_cards[:]:  # Iterate over copy
        if computer.can_play_card(card):
            # Check battlefield space for minions
            if card.is_minion and len(computer.board) >= 7:
                continue
                
            computer.play_card(card)
            add_battle_log(f"Computer plays {card.name}")
    
    # AI Strategy 3: Attack with minions
    for minion in computer.board:
        if minion.can_attack and minion.is_alive():
            # Prioritize attacking enemy minions
            if player.board:
                # Select optimal target (low health, high threat)
                target = min(player.board, 
                           key=lambda m: (m.health, -m.attack), 
                           default=None)
                if target:
                    minion.attack_target(target)
            else:
                # Attack champion directly
                player.health -= minion.attack
                add_battle_log(f"{minion.name} attacks {player.name} for {minion.attack} damage")
                minion.can_attack = False
    
    computer.end_turn()


# Draw start screen
def draw_start_screen():
    """Draw game start menu"""
    # Draw gradient background
    background_rect = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
    for y in range(SCREEN_HEIGHT):
        # Top to bottom gradient - red to blue
        r = int(100 + 30 * (1 - y/SCREEN_HEIGHT))
        g = int(20 + 20 * (1 - y/SCREEN_HEIGHT))
        b = int(20 + 80 * (y/SCREEN_HEIGHT))
        a = 255
        pygame.draw.line(background_rect, (r, g, b, a), (0, y), (SCREEN_WIDTH, y))
    screen.blit(background_rect, (0, 0))
    
    # Draw decorative elements
    for i in range(50):
        x = (i * 37) % SCREEN_WIDTH
        y = (i * 19) % SCREEN_HEIGHT
        # Twinkling effect
        brightness = (pygame.time.get_ticks() // 100 + i) % 5
        pygame.draw.circle(screen, (243, 173, 52, 150 + brightness * 20), (x, y), 1 + brightness // 2)
    
    # Draw Chinese style decorations
    draw_chinese_decorations(screen)
    
    # Draw game title
    title_font = pygame.font.SysFont(font_names, 64)
    title_text = title_font.render("League of ChangAn", True, CN_GOLD)
    title_rect = title_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 4))
    
    # Title shadow effect
    shadow_offset = 3
    shadow_surface = title_font.render("League of ChangAn", True, CN_BLACK)
    shadow_rect = shadow_surface.get_rect(center=(title_rect.centerx + shadow_offset, title_rect.centery + shadow_offset))
    screen.blit(shadow_surface, shadow_rect)
    screen.blit(title_text, title_rect)
    
    # Draw subtitle
    subtitle_font = pygame.font.SysFont(font_names, 32)
    subtitle_text = subtitle_font.render("Strategy Card Battle Game", True, WHITE)
    subtitle_rect = subtitle_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 3))
    screen.blit(subtitle_text, subtitle_rect)
    
    # Draw start game button
    start_btn = pygame.Rect(SCREEN_WIDTH // 2 - 80, SCREEN_HEIGHT // 2, 160, 50)
    screen.blit(BUTTON_BG, (SCREEN_WIDTH // 2 - 83, SCREEN_HEIGHT // 2 - 3))
    start_text = medium_font.render("Start Game", True, CN_GOLD)
    start_text_rect = start_text.get_rect(center=start_btn.center)
    screen.blit(start_text, start_text_rect)
    
    # Draw quit game button
    quit_btn = pygame.Rect(SCREEN_WIDTH // 2 - 80, SCREEN_HEIGHT // 2 + 70, 160, 50)
    screen.blit(BUTTON_BG, (SCREEN_WIDTH // 2 - 83, SCREEN_HEIGHT // 2 + 67))
    quit_text = medium_font.render("Quit Game", True, CN_GOLD)
    quit_text_rect = quit_text.get_rect(center=quit_btn.center)
    screen.blit(quit_text, quit_text_rect)
    
    # Draw game instructions
    info_font = pygame.font.SysFont(font_names, 18)
    info_text1 = info_font.render("Select cards to battle, defeat your opponent to win!", True, WHITE)
    info_text2 = info_font.render("Press SPACE to use champion skill, click End Turn to switch players", True, WHITE)
    screen.blit(info_text1, (SCREEN_WIDTH // 2 - info_text1.get_width() // 2, SCREEN_HEIGHT - 100))
    screen.blit(info_text2, (SCREEN_WIDTH // 2 - info_text2.get_width() // 2, SCREEN_HEIGHT - 70))
    
    return start_btn, quit_btn


# Game main function
def main():
    """Main game loop"""
    # Show start screen first
    show_start_screen = True
    clock = pygame.time.Clock()
    
    while show_start_screen:
        # Draw start screen
        start_btn, quit_btn = draw_start_screen()
        
        # Process events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                return
            
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                mouse_pos = event.pos
                
                # Check start button click
                if start_btn and start_btn.collidepoint(mouse_pos):
                    show_start_screen = False  # Enter game
                
                # Check quit button click
                if quit_btn and quit_btn.collidepoint(mouse_pos):
                    pygame.quit()
                    return
        
        pygame.display.flip()
        clock.tick(30)
    
    # Main game loop
    global selected_card, selected_minion, background_offset, hovered_card
    
    player1, player2 = init_game()
    current_player = player1
    game_over = False
    winner = None
    
    # Start first turn
    current_player.start_turn()
    
    while not game_over:
        # Draw game state and get buttons
        end_turn_btn, save_btn, load_btn, apply_btn = draw_game_state(player1, player2)
        
        # Process events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
                
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                mouse_pos = event.pos
                
                # Check button clicks
                if end_turn_btn and end_turn_btn.collidepoint(mouse_pos) and current_player == player1:
                    current_player.end_turn()
                    current_player = player2
                    computer_turn(current_player, player1)
                    current_player = player1
                
                if save_btn and save_btn.collidepoint(mouse_pos):
                    save_game_state(player1, player2)
                
                if load_btn and load_btn.collidepoint(mouse_pos):
                    loaded = load_game_state()
                    if loaded:
                        player1, player2 = loaded
                        current_player = player1
                
                # Apply button functionality
                if apply_btn and apply_btn.collidepoint(mouse_pos) and current_player == player1:
                    # Apply selected card or minion effects
                    if selected_card:
                        if player1.can_play_card(selected_card):
                            player1.play_card(selected_card)
                            selected_card = None
                            add_battle_log("Applied card effect")
                    elif selected_minion:
                        add_battle_log("Select a target for the minion")
                    else:
                        # Auto-equip best item if no selection
                        if player1.items:
                            best_item = max(player1.items, key=lambda x: getattr(x, 'attack_bonus', 0) + getattr(x, 'health_bonus', 0))
                            player1.equip_item(best_item)
                        else:
                            add_battle_log("No items to apply")
            
            # Player turn interactions
            if current_player == player1 and not game_over:
                if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                    mouse_pos = event.pos
                    
                    # Handle card selection
                    hand_y = 680
                    for card in player1.hand:
                        card_rect = pygame.Rect(200 + player1.hand.index(card) * 90, hand_y, 80, 120)
                        if card_rect.collidepoint(mouse_pos):
                            selected_card = card
                            selected_minion = None
                            break
                    
                    # Handle minion selection
                    board_y = 350
                    for minion in player1.board:
                        minion_rect = pygame.Rect(200 + player1.board.index(minion) * 90, board_y, 80, 120)
                        if minion_rect.collidepoint(mouse_pos):
                            selected_minion = minion
                            selected_card = None
                            break
                    
                    # Handle playing cards
                    if selected_card:
                        if player1.can_play_card(selected_card):
                            player1.play_card(selected_card)
                            selected_card = None
                    
                    # Handle minion attacks
                    if selected_minion and selected_minion.can_attack:
                        # Attack enemy minions
                        opp_board_y = 100
                        for target in player2.board:
                            target_rect = pygame.Rect(200 + player2.board.index(target) * 90, opp_board_y, 80, 120)
                            if target_rect.collidepoint(mouse_pos):
                                selected_minion.attack_target(target)
                                selected_minion = None
                                break
                        else:
                            # Attack enemy champion
                            hero_rect = pygame.Rect(50, 20, 100, 150)
                            if hero_rect.collidepoint(mouse_pos):
                                player2.health -= selected_minion.attack
                                add_battle_log(f"{selected_minion.name} attacks {player2.name} for {selected_minion.attack} damage")
                                selected_minion.can_attack = False
                                selected_minion = None
            
            # Champion skill usage (spacebar)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and current_player == player1:
                    # Use champion skill
                    target = None
                    if isinstance(player1.champion, LadyLin) and player2.board:
                        target = player2.board[0]  # Select first target
                    elif isinstance(player1.champion, AlchemistZhou) and player1.board:
                        target = player1.board[0]
                    
                    player1.use_champion_skill(target)
        
        # Update background animation
        background_offset = (background_offset + 1) % SCREEN_WIDTH
        
        # Check game over conditions
        if player1.health <= 0:
            game_over = True
            winner = player2
        elif player2.health <= 0:
            game_over = True
            winner = player1
        
        # Show game over screen
        if game_over:
            # Create semi-transparent overlay
            overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
            overlay.fill((0, 0, 0, 180))
            screen.blit(overlay, (0, 0))
            
            # Draw victory text
            game_over_text = large_font.render(f"{winner.name} wins!", True, CN_GOLD)
            screen.blit(game_over_text, (SCREEN_WIDTH//2 - game_over_text.get_width()//2, 
                                        SCREEN_HEIGHT//2 - game_over_text.get_height()//2))
        
        pygame.display.flip()
        clock.tick(30)
    
    pygame.quit()


if __name__ == "__main__":
    pygame.init()
    main()